package com.novax.ex.activity.provider.service;

import com.novax.ex.activity.infrastructure.entity.*;
import com.novax.ex.activity.infrastructure.mapper.*;
import com.novax.ex.activity.open.model.query.IeoConfigQuery;
import com.novax.ex.activity.open.model.request.IeoActivityRequest;
import com.novax.ex.activity.open.model.request.IeoConfigRequest;
import com.novax.ex.activity.open.model.response.*;
import com.novax.ex.activity.provider.api.ActivityInfoApi;
import com.novax.ex.activity.provider.api.InternationalApi;
import com.novax.ex.activity.provider.api.model.UserActivityInfo;
import com.novax.ex.common.base.BaseMapper;
import com.novax.ex.common.base.BaseService;
import com.novax.ex.common.enums.ProjectStatus;
import com.novax.ex.common.results.ReturnResult;
import com.novax.ex.common.util.CopyUtils;
import com.novax.ex.common.util.DateUtil;
import com.novax.ex.common.util.JWTUtil;
import com.novax.ex.common.util.PageUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;

import jakarta.annotation.Resource;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @Description 活动配置Service
 * @Author Cody
 * @Date 2022/12/01/18:04
 */
@Service
@Slf4j
public class IeoConfigService extends BaseService {

    @Resource
    private IeoConfigMapper ieoConfigMapper;

    @Resource
    private IeoCurrencyConfigMapper ieoCurrencyConfigMapper;

    @Resource
    private IeoVipLimitMapper ieoVipLimitMapper;

    @Resource
    private IeoRuleMapper ieoRuleMapper;

    @Resource
    private IeoContentMapper ieoContentMapper;

    @Resource
    private IeoOrderService ieoOrderService;

    @Resource
    private IeoCurrencyConfigService ieoCurrencyConfigService;

    @Resource
    private InternationalApi internationalApi;

    @Resource
    private ActivityInfoApi activityInfoApi;

    @Resource
    private IeoOrderMapper ieoOrderMapper;

    // 默认VIP限购数配置
    private static ArrayList<IeoVipLimit> defaultIeoVipLimits = new ArrayList<>();

    static {
        defaultIeoVipLimits.add(new IeoVipLimit(0, 0));
        defaultIeoVipLimits.add(new IeoVipLimit(1, 1));
        defaultIeoVipLimits.add(new IeoVipLimit(2, 5));
        defaultIeoVipLimits.add(new IeoVipLimit(3, 10));
        defaultIeoVipLimits.add(new IeoVipLimit(4, 30));
        defaultIeoVipLimits.add(new IeoVipLimit(5, 50));
        defaultIeoVipLimits.add(new IeoVipLimit(6, 100));
        defaultIeoVipLimits.add(new IeoVipLimit(7, 200));
        defaultIeoVipLimits.add(new IeoVipLimit(8, 500));
        defaultIeoVipLimits.add(new IeoVipLimit(9, 900));
    }

    @Override
    protected BaseMapper getBaseMapper() {
        return ieoConfigMapper;
    }

    /**
     * 黄涛
     * 发现内容和规则
     *
     * @param ieoId    ieo id
     * @param language 语言
     * @return {@link ContentAndRule}
     */
    public ContentAndRule findContentAndRule(Long ieoId, String language) {
        IeoRule ieoRule = ieoRuleMapper.selectByIeoIdAndLanguage(ieoId, language);
        IeoContent ieoContent = ieoContentMapper.selectContentByIeoIdAndLanguage(ieoId, language);
        ContentAndRule contentAndRule = new ContentAndRule();
        if (Objects.nonNull(ieoContent)) {
            contentAndRule.setContent(ieoContent.getContent());
        }
        if (Objects.nonNull(ieoRule)) {
            contentAndRule.setRule(ieoRule.getRule());
        }
        return contentAndRule;
    }

    /**
     * 黄涛
     * 后台活动配置的分页查询方法
     *
     * @param query 分页查询需要的参数 根据活动币种和活动状态去分页
     * @return 分页数据
     */
    public PageUtil<IeoConfigResponse> findByPage(IeoConfigQuery query) {
        PageUtil<IeoConfigResponse> page = new PageUtil<>(query);
        page.setCondition(Collections.singletonMap("query", query));
        findExtPage(page, IeoConfigResponse.class);
        for (IeoConfigResponse item : page.getItems()) {
            item.setMultiple(displayMultiple(item.getDisplayCount(), item.getMultiple(), item.getPortion()));
        }
        return page;
    }

    // 条件分页查询
    public <T> void findExtPage(PageUtil<T> pageInfo, Class<T> clazz) {
        long total = getBaseMapper().count(pageInfo);
        pageInfo.setTotal(total);
        if (total > 0) {
            List<IeoConfigAndStagesList> ieoConfigAndStagesLists = getBaseMapper().selectPage(pageInfo);
            // 期数升序
            ieoConfigAndStagesLists.forEach(s  -> s.getIeoStagesList().sort(Comparator.comparing(IeoExtStages::getStagesNumber)));
            pageInfo.setItems((List<T>) CopyUtils.copyList(ieoConfigAndStagesLists, IeoConfigResponse.class));
        } else {
            pageInfo.setItems(new ArrayList<>());
        }
    }

    /**
     * @Description: 添加活动配置时批量添加默认的VIP限购数配置
     * @Author: ChenXi
     * @Date: 2022/12/10 09:39
     * @Param: [configRequest]
     * @return: boolean
     **/
    @Transactional(rollbackFor = Exception.class)
    public boolean addAndBatchInsertVipLimit(IeoConfigRequest configRequest) {
        IeoConfig ieoConfig = CopyUtils.copyObject(configRequest, IeoConfig.class);
        ieoConfig.setCreateTime(new Date());
        ieoConfig.setSharePortion(configRequest.getPortion());
        // 创建币种活动后自动生成vip各等级限购数
        boolean res = ieoConfigMapper.insertSelective(ieoConfig) > 0;
        if (!defaultIeoVipLimits.isEmpty()) {
            for (IeoVipLimit defaultIeoVipLimit : defaultIeoVipLimits) {
                defaultIeoVipLimit.setIeoId(ieoConfig.getId());
                defaultIeoVipLimit.setCreateTime(new Date());
            }
        }
        // 批量添加
        int i = ieoVipLimitMapper.batchInsert(defaultIeoVipLimits);
        ieoCurrencyConfigService.addDefaultCurrency(ieoConfig.getId());
        // 活动配置添加成功且vip默认限购配置添加成功
        return res && i >= defaultIeoVipLimits.size();
    }


    /**
     * 黄涛
     * 查询所有ieo所有活动
     *
     * @param status 状态 目前活动所处的状态
     * @return {@link List}<{@link IeoResponse}>
     */
    public List<IeoResponse> getAllActivity(Integer status) {
        List<IeoExtConfig> list;
        if(status == 4){
            list = ieoConfigMapper.selectAllConfigs();
        } else {
            list = ieoConfigMapper.selectConfigs(status, new Date());
        }

        return activity(list, status);
    }

    /**
     * 黄涛
     * 分页查询ieo所有活动
     *
     * @param ieoActivityRequest ieo活动要求
     * @return {@link PageUtil}<{@link IeoConfig}>
     */
    public PageUtil<IeoConfig> findByPage(IeoActivityRequest ieoActivityRequest) {
        PageUtil<IeoConfig> pageUtil = new PageUtil<>(ieoActivityRequest);
        pageUtil.setCondition(Collections.singletonMap("query", ieoActivityRequest));
        findPage(pageUtil);
        return pageUtil;
    }

    /**
     * 黄涛
     * 获得活动信息
     *
     * @param language 语言
     * @param id       id
     * @return {@link IeoInfoResponse}
     */
    public IeoInfoResponse getActivityInfo(String token, String language, Long id) {
        // ieo活动的配置信息
        IeoConfig ieoConfig = ieoConfigMapper.selectByPrimaryKey(id);

        if (Objects.isNull(ieoConfig)) return null;

        // 如果没配解锁时间, 返回前台 结束时间5天后 的时间
        IeoInfoResponse ieoInfoResponse = CopyUtils.copyObject(ieoConfig, IeoInfoResponse.class);

        // 活动卖出了多少份
        Integer copies = ieoOrderService.findSumCopiesByIeoId(ieoConfig.getId());
        if (Objects.isNull(copies)) {
            copies = 0;
        }
        // 活动转计价币种单位的数量
        IeoCurrencyConfig isPricingCurrency = ieoCurrencyConfigMapper.findByIsPricingCurrency(ieoConfig.getId());
        BigDecimal amountOfCopies = isPricingCurrency.getAmount();
        ieoInfoResponse.setIsPriceCurrency(isPricingCurrency.getCurrency());
        // 卖出的币转计价币种
        BigDecimal count = amountOfCopies.multiply(new BigDecimal(copies));

        // 期望卖出多少币
        BigDecimal expect;
        if (Objects.isNull(ieoConfig.getDisplayCount()) || ieoConfig.getDisplayCount() == 0) {
            expect = new BigDecimal(ieoConfig.getPortion()).multiply(amountOfCopies);
        } else {
            expect = amountOfCopies.multiply(new BigDecimal(ieoConfig.getDisplayCount()));
        }

        // 手动设置的膨胀倍数 默认是不加倍
        BigDecimal multiple = displayMultiple(ieoConfig.getDisplayCount(), ieoConfig.getMultiple(), ieoConfig.getPortion());

        // 支持者
        ieoInfoResponse.setSupporter(multiple.multiply(new BigDecimal(ieoOrderService.supporterCount(id))).setScale(0, RoundingMode.UP).intValue());

        // 设置已筹款金额（去除所有小数 四舍五入）
        ieoInfoResponse.setIsPriceRaised(multiple.multiply(count).setScale(0, RoundingMode.HALF_UP));

        // 目标筹款金额
        ieoInfoResponse.setIsPriceExpectAmount(expect.setScale(0, RoundingMode.HALF_UP));

        // 设置已达百分比
        ieoInfoResponse.setReached(ieoInfoResponse.getIsPriceRaised().divide(expect, 4, RoundingMode.DOWN));

        // 总份数
        if (ieoConfig.getDisplayCount() != null && ieoConfig.getDisplayCount() != 0) {
            ieoInfoResponse.setTotalCopies(ieoConfig.getDisplayCount());
        } else {
            ieoInfoResponse.setTotalCopies(ieoConfig.getPortion());
        }

        // 查询此ieo所有币种
        List<IeoCurrencyConfig> ieoCurrencyConfigs = ieoCurrencyConfigMapper.selectByIeoId(id);
        List<CurrencyInfo> currencyAndUserInfo = Collections.emptyList() ;

        // 如果已登录, 查询此币种用户可购买多少份, 以及余额
        if(StringUtils.hasText(token)){
            Long userId = JWTUtil.getUid(token);
            if(Objects.nonNull(userId)){
                currencyAndUserInfo = inquiryPurchasePower(ieoCurrencyConfigs, userId, ieoConfig, ieoInfoResponse);
            }
        }
        if(currencyAndUserInfo.isEmpty()){
            currencyAndUserInfo = CopyUtils.copyList(ieoCurrencyConfigs, CurrencyInfo.class);
        }
        ieoInfoResponse.setAmountOfCopy(currencyAndUserInfo);
        ContentAndRule contentAndRule = findContentAndRule(id, language);
        // 活动规则
        ieoInfoResponse.setRules(
                Objects.isNull(contentAndRule.getRule()) ?
                        findContentAndRule(id, Locale.US.getLanguage()).getRule() : contentAndRule.getRule());
        // 活动介绍
        ieoInfoResponse.setIntroduce(
                Objects.isNull(contentAndRule.getContent()) ?
                        findContentAndRule(id, Locale.US.getLanguage()).getContent() : contentAndRule.getContent());
        // 活动状态
        ieoInfoResponse.setStatus(getProjectStatus(ieoConfig.getStartTime(), ieoConfig.getEndTime()).getCode());
        // 支持/ 每份
        ieoInfoResponse.setAmountOfCopies(ieoConfig.getAmount());

        if(Objects.isNull(ieoConfig.getUnlockTime())){
            ieoInfoResponse.setUnlockTime(DateUtil.addDay(ieoConfig.getEndTime(), 5));
        } else {
            ieoInfoResponse.setUnlockTime(ieoConfig.getUnlockTime());
        }

        // 设置注册天数
        ieoInfoResponse.setRegisterDays(ieoConfig.getRegister());

        // 兼容旧版本
        // 计价币种转USDT汇率
        BigDecimal usdtRate = isPricingCurrency.getUsdtRate();
        ieoInfoResponse.setExpectAmount(ieoInfoResponse.getIsPriceExpectAmount().multiply(usdtRate).setScale(0, RoundingMode.HALF_UP));
        ieoInfoResponse.setRaised(ieoInfoResponse.getIsPriceRaised().multiply(usdtRate).setScale(0, RoundingMode.HALF_UP));

        return ieoInfoResponse;
    }

    /**
     * @Description: 查询此币种用户可购买多少份, 以及余额
     * @Author: ChenXi
     * @Date:  2023/5/9 17:04
     * @param ieoCurrencyConfigs
     * @param userId
     * @param ieoConfig
     * @param ieoInfoResponse
     * @return: void
     **/
    private List<CurrencyInfo> inquiryPurchasePower(List<IeoCurrencyConfig> ieoCurrencyConfigs, Long userId,
                                                    IeoConfig ieoConfig,
                                                    IeoInfoResponse ieoInfoResponse) {
        if(Objects.isNull(ieoConfig)){
            return Collections.emptyList();
        }

        Long ieoId = ieoConfig.getId();

        // 查询用户信息
        ReturnResult<UserActivityInfo> info = activityInfoApi.findInfo(userId);
        if(Objects.isNull(info) || Objects.isNull(info.getData())){
            return Collections.emptyList();
        }

        // 获取该用户购买过的份数
        Integer totalNumberCopies = ieoOrderMapper.selectCopiesSumByUserIdAndIeoId(userId, ieoId);
        if (Objects.isNull(totalNumberCopies)) {
            totalNumberCopies = 0;
        }

        // 已购买数
        ieoInfoResponse.setCopiesPurchase(totalNumberCopies);
        // 用户信息
        UserActivityInfo userActivityInfo = info.getData();

        // 判断vip等级
        Integer vipLevel = ieoConfig.getVipLimit();
        Integer userVipLevel = userActivityInfo.getVipLevel();
        if (userVipLevel < vipLevel) {
            return Collections.emptyList();
        }

        // 用户vip等级限购数
        IeoVipLimit ieoVipLimit = ieoVipLimitMapper.selectByIeoIdAndVipLevel(ieoId, userVipLevel);
        Integer vipLimit = Objects.nonNull(ieoVipLimit) ? ieoVipLimit.getLimit() : 0 ;

        // 用户剩余可购买数
        int remainingLimit  = vipLimit - totalNumberCopies;

        if(remainingLimit <= 0){
            return Collections.emptyList();
        }

        ieoInfoResponse.setRemainingLimit(remainingLimit);

        List<CurrencyInfo> currencyInfos = new ArrayList<>();
        for (IeoCurrencyConfig ieoCurrencyConfig : ieoCurrencyConfigs) {
            // 用户剩余可购买数 (BigDecimal)
            BigDecimal remainingLimit2BigDecimal = new BigDecimal(remainingLimit);
            // 查询用户余额能购买的份数
            Map<String, BigDecimal> map = ieoOrderService.getCopiesByCurrency(ieoCurrencyConfig, userId);
            // 可购买份数
            BigDecimal copiesByCurrency = Optional.ofNullable(map.get("copiesByCurrency")).orElseGet(() -> BigDecimal.ZERO);
            // 用户余额
            BigDecimal userAmount = Optional.ofNullable(map.get("userAmount")).orElseGet(() -> BigDecimal.ZERO);
            userAmount = userAmount.setScale(8, RoundingMode.UP);
            userAmount = userAmount.stripTrailingZeros();

            CurrencyInfo currencyInfo = CopyUtils.copyObject(ieoCurrencyConfig, CurrencyInfo.class);
            if(copiesByCurrency.compareTo(remainingLimit2BigDecimal) >= 0 ){
                currencyInfo.setCopies(remainingLimit2BigDecimal);
            } else {
                currencyInfo.setCopies(copiesByCurrency);
            }
            currencyInfo.setUserAmount(userAmount);
            currencyInfos.add(currencyInfo);
        }
        return currencyInfos;
    }

    /**
     * 黄涛
     * IEO活动的详情
     *
     * @return {@link List}<{@link IeoResponse}>
     */
    public List<IeoResponse> activity(List<IeoExtConfig> ieoConfigs, Integer status) {
        List<IeoResponse> resp = new ArrayList<>();
        ieoConfigs.forEach(x -> {
            IeoResponse ieoResponse = new IeoResponse();
            ieoResponse.setId(x.getId());
            ieoResponse.setImg(x.getImg());
            ieoResponse.setStartTime(x.getStartTime());
            ieoResponse.setEndTime(x.getEndTime());
            ieoResponse.setIncreaseHistory(x.getIncreaseHistory());
            Integer openState = x.getOpenState();

            if(Objects.isNull(openState)){
                Date startTime = x.getStartTime();
                Date endTime = x.getEndTime();
                Date now = new Date();
                if(now.before(startTime)){
                    ieoResponse.setStatus(0);
                } else if(now.after(endTime)){
                    ieoResponse.setStatus(2);
                } else {
                    ieoResponse.setStatus(1);
                }
            } else {
                if(0 == openState){
                    ieoResponse.setStatus(2);
                } else if(1 == openState){
                    ieoResponse.setStatus(0);
                } else {
                    ieoResponse.setStatus(1);
                }

            }

            ieoResponse.setProjectName(x.getProjectName());
            ieoResponse.setCurrency(x.getCurrency());

            // 该活动每一份币转为计价货币的数量
            IeoCurrencyConfig ieoCurrencyConfig = ieoCurrencyConfigMapper.findByIsPricingCurrency(x.getId());
            BigDecimal amountOfCopies = ieoCurrencyConfig.getAmount();
            // 计价币种
            String currency = ieoCurrencyConfig.getCurrency();
            ieoResponse.setIsPriceCurrency(currency);
            // 活动总共卖出份数
            Integer copies = ieoOrderService.findSumCopiesByIeoId(x.getId());

            // 手动加倍，这里限制掉默认为1，否则采用加倍后的数量
            BigDecimal multipleByHand = displayMultiple(x.getDisplayCount(), x.getMultiple(), x.getPortion());

            // 已筹款金额(去除所有小数 四舍五入) 总份数*每份金额
            BigDecimal bigDecimal = amountOfCopies.multiply(new BigDecimal(copies))
                    .multiply(multipleByHand)
                    .setScale(0, RoundingMode.HALF_UP);

            ieoResponse.setIsPriceRaised(bigDecimal);
            // 当配置了前台显示认购份数的时候：期望筹集到的金额应=前台显示认购份数*每份USDT数量
            // 当未配置前台显示认购份数的时候：期望筹集到的金额就是全部卖出
            // 期望卖出多少币
            BigDecimal expect;
            if (Objects.isNull(x.getDisplayCount()) || x.getDisplayCount() == 0) {
                expect = amountOfCopies.multiply(new BigDecimal(x.getPortion()));
            } else {
                expect = amountOfCopies.multiply(new BigDecimal(x.getDisplayCount()));
            }
            ieoResponse.setIsPriceExpectAmount(expect.setScale(0, RoundingMode.HALF_UP));
            if(expect.compareTo(BigDecimal.ZERO) == 0){
                ieoResponse.setReached(BigDecimal.ZERO);
            } else {
                ieoResponse.setReached(bigDecimal.divide(expect, 4, RoundingMode.DOWN));
            }

            // 兼容旧版本
            // 计价币种转USDT汇率
            BigDecimal usdtRate = ieoCurrencyConfig.getUsdtRate();
            ieoResponse.setExpectAmount(ieoResponse.getIsPriceExpectAmount().multiply(usdtRate).setScale(0, RoundingMode.HALF_UP));
            ieoResponse.setRaised(ieoResponse.getIsPriceRaised().multiply(usdtRate).setScale(0, RoundingMode.HALF_UP));
            resp.add(ieoResponse);
        });

        if(status == 3){
            List<IeoResponse> list = resp.stream()
                .sorted(Comparator.comparing(IeoResponse::getStatus).reversed()
                            .thenComparing(IeoResponse::getEndTime) )
                .collect(Collectors.toList());
            return list;
        }

        return resp;
    }

    /**
     * 黄涛
     * 通过得到项目状态
     *
     * @param startTime 开始时间
     * @param endTime   结束时间
     * @return {@link ProjectStatus}
     */
    private ProjectStatus getProjectStatus(Date startTime, Date endTime) {
        Date date = new Date();
        // 获取当前时间的时间戳
        long nowTime = date.getTime();
        long start = startTime.getTime();
        long end = endTime.getTime();
        if (end < nowTime) {
            return ProjectStatus.END;
        } else if (start > nowTime) {
            return ProjectStatus.NOT_START;
        } else {
            return ProjectStatus.PENDING;
        }
    }

    private BigDecimal displayMultiple(Integer displayCount, BigDecimal multiple, Integer portion) {
        if (Objects.isNull(multiple) || multiple.compareTo(BigDecimal.ZERO) == 0) {
            // 如果没有配置前台显示份数，那么就按照1倍来计算
            if (Objects.isNull(displayCount) || displayCount == 0) {
                return BigDecimal.ONE;
            }
            BigDecimal dis = new BigDecimal(displayCount);
            BigDecimal por = new BigDecimal(portion);
            return dis.divide(por, 4, RoundingMode.CEILING);
        }
        return multiple.setScale(4, RoundingMode.CEILING);
    }

    @Transactional(rollbackFor = RuntimeException.class)
    public boolean modifyAndCalculate(IeoConfig ieoConfig) {
        int i = ieoConfigMapper.updateByPrimaryKeySelective(ieoConfig);
        if(i >= 1){
            ieoOrderService.calculate(ieoConfig);
        }
        return i >= 1 ;
    }

    /**
     * @Description: 查询所有应发币的分期IEO
     * @Author: ChenXi
     * @Date:  2023/5/6 11:09
     * @param
     * @return: java.util.List<com.novax.ex.activity.infrastructure.entity.IeoConfig>
     **/
    public List<IeoConfig> findAllStageIeo() {
        return ieoConfigMapper.findAllStageIeo();
    }

    /**
     * 获取国际化翻译
     *
     * @param language language
     * @param code     国际化编码
     * @return string 国际化
     */
    protected String getInternational(String language, String code) {
        return internationalApi.getInternational(code, language).getData();
    }

    /**
     * @Description: 订单记录发放记录搜索下拉框
     * @Author: ChenXi
     * @Date:  2023/5/17 14:19
     * @param
     * @return: com.novax.ex.common.results.ReturnResult<java.util.List<java.lang.String>>
     **/
    public List<String> queryBox() {
        return ieoConfigMapper.queryBox();
    }

}
